﻿using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;

namespace RG.Common.WPF
{
    /// <summary>
    /// Base class for all ViewModel classes displayed by TreeViewItems.  
    /// This acts as an adapter between a raw data object and a TreeViewItem.
    /// </summary>
    public class TreeViewItemViewModel :INotifyPropertyChanged, IFirePropertyChanged
    {

        #region Data
        static readonly TreeViewItemViewModel DummyChild = new TreeViewItemViewModel();

        private readonly ObservableCollection<TreeViewItemViewModel> childs = new ObservableCollection<TreeViewItemViewModel>();
        private readonly List<TreeViewItemViewModel> _checkedDesc = new List<TreeViewItemViewModel>();

        /// <summary>
        /// В TreeView нужно устанавливать SelectedItem в событии Loaded.
        /// Если Установить заранее в ещё не прибинденной ViewModel, то нет эффекта
        /// </summary>
        public static TreeViewItemViewModel SelectWhenLoaded;

        public static List<TreeViewItemViewModel> CheckedWhenLoaded;

        private readonly TreeViewItemViewModel parent;
        private bool _IsChecked;
        private bool _HasLowerCheckedItems;
        private bool isExpanded;
        private bool isSelected;
        private bool hasChilds;
        private TreeViewItemViewModel selectedItem;
        #endregion // Data

        #region Constructors

        protected TreeViewItemViewModel(TreeViewItemViewModel parent)
        {
            this.parent = parent;
        }

        // This is used to create the DummyChild instance.
        public TreeViewItemViewModel()
        { }

        #endregion // Constructors

        #region Presentation Members

        /// <summary>
        /// Returns the logical child items of this object.
        /// </summary>
        public ObservableCollection<TreeViewItemViewModel> Childs
        {
            get { return childs; }
        }
        /// <summary>
        /// список всех чекнутых потомков
        /// </summary>
        public List<TreeViewItemViewModel> CheckedDescendants
        {//todo - наверно надо сделать readonly?
            get { return _checkedDesc; }
        }
        public bool HasChilds
        {
            get { return hasChilds; }
            set
            {
                if (hasChilds != value)
                {
                    hasChilds = value;
                    childs.Clear();
                    if (hasChilds)
                        childs.Add(DummyChild);
                }
            }
        }

        /// <summary>
        /// Returns true if this object's Children have not yet been populated.
        /// </summary>
        public bool NeedLoadChilds
        {
            get { return (childs.Count == 1) && (childs[0] == DummyChild); }
        }

        /// <summary>
        /// Нужен для ручного заполнения в наследниках
        /// </summary>
        /// <param name="?"></param>
        protected void AddChild(TreeViewItemViewModel child)
        {
            // На всякий случай сносим Dummy-детей
            if (NeedLoadChilds)
                childs.Clear();
            childs.Add(child);
            hasChilds = true;
        }

        #region IsExpanded

        /// <summary>
        /// Gets/sets whether the TreeViewItem 
        /// associated with this object is expanded.
        /// </summary>
        public bool IsExpanded
        {
            get { return isExpanded; }
            set
            {
                if (value != isExpanded)
                {
                    isExpanded = value;
                    OnPropertyChanged("IsExpanded");
                }

                // Expand all the way up to the root.
                if (isExpanded && parent != null)
                    parent.IsExpanded = true;

                // Lazy load the child items, if necessary.
                if (NeedLoadChilds)
                {
                    childs.Clear();
                    LoadChildren();
                }
            }
        }

        #endregion // IsExpanded

        #region IsSelected

        /// <summary>
        /// Gets/sets whether the TreeViewItem 
        /// associated with this object is selected.
        /// </summary>
        public bool IsSelected
        {
            get { return isSelected; }
            set
            {
                if (value != isSelected)
                {
                    isSelected = value;
                    OnPropertyChanged("IsSelected");
                    var root = this;
                    while (root.Parent != null) root = root.Parent;
                    root.SelectedItem = this;
                }
            }
        }

        #endregion // IsSelected


        #region IsChecked

        /// <summary>
        /// свойство которое будем забиндивать на IsChecked чекбокса в темплейте для этого итема
        /// </summary>
        public bool IsChecked
        {
            get { return _IsChecked; }
            set
            {
                if (value != _IsChecked)
                {
                    _IsChecked = value;
                    OnPropertyChanged("IsChecked");
                    var curParent = this.parent;
                    while(curParent!=null)
                    {
                        if (value)
                            curParent.CheckedDescendants.Add(this);
                        else
                            curParent.CheckedDescendants.Remove(this);

                        curParent.HasLowerCheckedItems = curParent.CheckedDescendants.Count > 0;
                        curParent = curParent.parent;
                    }
                }
            }
        }
     
        public bool HasLowerCheckedItems
        {
            get { return _HasLowerCheckedItems; }
          private  set
            {
                if (value == _HasLowerCheckedItems) return;
                _HasLowerCheckedItems = value;
                OnPropertyChanged("HasLowerCheckedItems");
            }
        }
        #endregion

        #region SelectedItem

        public virtual TreeViewItemViewModel SelectedItem
        {
            get { return selectedItem; }
            set
            {
                if (selectedItem != value)
                {
                    selectedItem = value;
                    OnPropertyChanged("SelectedItem");
                }
            }
        }
        #endregion

        #region LoadChildren

        /// <summary>
        /// Invoked when the child items need to be loaded on demand.
        /// Subclasses can override this to populate the Children collection.
        /// </summary>
        protected internal virtual void LoadChildren()
        {
        }

        #endregion // LoadChildren

        #region Parent

        public TreeViewItemViewModel Parent
        {
            get { return parent; }
        }

        #endregion // Parent

        #endregion // Presentation Members

        #region CheckUncheckMethods
        public void UnCheckAllDescendants()
        {
            var tmpLst = new List<TreeViewItemViewModel>();
            foreach (var d in CheckedDescendants)
                tmpLst.Add(d);
            foreach (var d in tmpLst)
                d.IsChecked = false;
            //в сеттере здесь модифицируется CheckedDescendants поэтому приходится извращаться потому как не можем модифицировать список при foreach по нему
        }

        public void CheckAllChilds()
        {
            LoadChildren();
            foreach (var d in Childs)
                d.IsChecked = true;
        }
        #endregion

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        public void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

        #endregion // INotifyPropertyChanged Members
    }
    /// <summary>
    /// копия класса с другим названием - чтобы механизм вытаскивания шаблона по названию типа сработал когда нужны чекбоксы для мультиселекта
    /// </summary>
    public class TreeViewItemViewModelForMultiSelect : TreeViewItemViewModel
    {
   #region Constructors

        protected TreeViewItemViewModelForMultiSelect(TreeViewItemViewModel parent):base(parent)
        {
        }

        // This is used to create the DummyChild instance.
        public TreeViewItemViewModelForMultiSelect()
        { }

        #endregion // Constructors
    }

}